﻿using Newtonsoft.Json.Linq;
using Simple.Tools.Map.Check;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;


namespace Simple.Tools
{
	/// <summary>
	/// 
	/// </summary>
    public static class AttributeExtension
    {
		/// <summary>
		/// 
		/// </summary>

		/// <summary>
		/// 
		/// </summary>
	

        static AttributeExtension()
		{
		
		
        }
		/// <summary>
		/// 
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
        public static string GetClassName(this Type type)
        {
            if (type.IsDefined(typeof(ClassNameAttribute), false))
            {
                ClassNameAttribute classNameAttribute = type.GetCustomAttribute<ClassNameAttribute>(false);
                return classNameAttribute.GetName();
            }
            else
            {
                return type.Name;
            }
        }
		/// <summary>
		/// 获取属性列的自定义名称
		/// </summary>
		/// <param name="prop"></param>
		/// <returns></returns>
        public static string GetColName(this PropertyInfo prop)
        {
            if (prop.IsDefined(typeof(ColNameAttribute), false))
            {
                ColNameAttribute classNameAttribute = prop.GetCustomAttribute<ColNameAttribute>(false);
                return classNameAttribute.GetName();
            }
            else
            {
                return prop.Name;
            }
        }
		/// <summary>
		/// 获取字段的重新定义的名称
		/// </summary>
		/// <param name="field"></param>
		/// <returns></returns>
		public static string GetColName(this FieldInfo field)
		{
			if (field.IsDefined(typeof(ColNameAttribute), false))
			{
				ColNameAttribute classNameAttribute = field.GetCustomAttribute<ColNameAttribute>(false);
				return classNameAttribute.GetName();
			}
			else
			{
				return field.Name;
			}
		}
		/// <summary>
		/// 返回枚举类型的描述信息
		/// </summary>
		/// <param name="e"></param>
		/// <returns></returns>
		public static string GetDescription(this Enum e)
		{
			Type type=e.GetType();
			if (type.IsDefined(typeof(DescriptionAttribute), false))
			{
				DescriptionAttribute classNameAttribute = type.GetCustomAttribute<DescriptionAttribute>(false);
				return classNameAttribute.GetDescription();
			}
			else
			{
				return type.Name;
			}
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="methodInfo"></param>
		/// <returns></returns>
		public static string GetMethodName(this MethodInfo methodInfo)
        {
            if (methodInfo.IsDefined(typeof(MethodNameAttribute)))
            {
				MethodNameAttribute classNameAttribute = methodInfo.GetCustomAttribute<MethodNameAttribute>();
				return classNameAttribute.GetName();
            }
            else
            {
                return methodInfo.Name;
            }
        }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
        public static IEnumerable<PropertyInfo> GetNoIgnore(this Type type)
        {
            IEnumerable<PropertyInfo> props=type.GetProperties().
                Where(t=>t.IsDefined(typeof(IgnoreAttribute),false)==false);
            if (props==null )
            {
                return null;
            }
            return props;
        }
        /// <summary>
		/// 
		/// </summary>
		/// <param name="type"></param>
		/// <param name="func"></param>
		/// <returns></returns>
        public static IEnumerable<PropertyInfo> GetNoIgnore(this Type type,Func<PropertyInfo,bool> func)
        {
            IEnumerable<PropertyInfo> props = type.GetProperties().
                Where(t=>func.Invoke(t));
            if (props == null)
            {
                return null;
            }
            return props;
        }
        /// <summary>
        /// 当程序程序集中找出继承type的类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
		public static IEnumerable<Type> GetChildrenClass(this Type type)
		{
			List<Type> types = new List<Type>();
			var assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (var assembliy in assemblies)
			{
				foreach (var itemType in assembliy.GetTypes())
				{
					
					//if (itemType.IsAssignableTo(type)).net core 6

					if (type.IsAssignableFrom(itemType))
					{
						types.Add(itemType);
					}
				}
			}
			return types;
		}

		/// <summary>
		/// 映射成字典
		/// </summary>
		/// <typeparam name="TValue"></typeparam>
		/// <param name="tValue"></param>
		/// <param name="childPropertyJoinChar"></param>
		/// <returns></returns>
		public static Dictionary<string, object> MapToDictionary<TValue>(this TValue tValue, char childPropertyJoinChar = '_') where TValue : class
		{
			SimpleCheck.IsNullThrowException(tValue);

			Dictionary<string, object> dic = new Dictionary<string, object>();
			Type type = typeof(TValue);
			foreach (var property in type.GetProperties())
			{
				PropertyToDictionary(dic, property, tValue, childPropertyJoinChar);
			}
			return dic;
		}

		/// <summary>
		///对象中的属性的值映射成字典
		/// </summary>
		/// <param name="dic">字典存储属性中的字段名称和值</param>
		/// <param name="property">目标属性</param>
		/// <param name="tValue">目标对象</param>
		/// <param name="childPropertyJoinChar">父属性与子属性之间的链接符</param>
		/// <param name="parentName">父属性名称</param>
		private static void PropertyToDictionary(Dictionary<string, object> dic, PropertyInfo property, object tValue, char childPropertyJoinChar, string parentName = null)
		{
			// Console.WriteLine(property.GetColName());
			if (property.IsDefined(typeof(IgnoreAttribute)))
			{
				return;
			}
			if (property.PropertyType.IsValueType || property.PropertyType == typeof(string))
			{
				object value = property.GetValue(tValue);
				string key = string.Empty;
				if (SimpleCheck.IsNullOrEmpty(parentName))
				{
					key = property.GetColName();
				}
				else
				{
					if (string.IsNullOrEmpty(property.GetColName()))
					{
						key = $"{parentName}{property.GetColName()}";
					}
					else
					{
						key = $"{parentName}{childPropertyJoinChar}{property.GetColName()}";
					}
				}

				if (!dic.ContainsKey(key))
				{
					dic.Add(key, value);
				}
			}
			else if (
				!property.PropertyType.IsArray &&
				property.PropertyType.IsClass &&
				!property.PropertyType.IsGenericType)
			{
				foreach (PropertyInfo childProperty in property.PropertyType.GetProperties())
				{
					object childValue = property.GetValue(tValue);
					string name = property.GetColName();
					if (!SimpleCheck.IsNullOrEmpty(parentName))
					{
						name = $"{parentName}{childPropertyJoinChar}{name}";
					}
					PropertyToDictionary(dic, childProperty, childValue, childPropertyJoinChar, name);
				}
			}
		}

		/// <summary>
		///字典映射成对象
		/// </summary>
		/// <typeparam name="TValue"></typeparam>
		/// <param name="tValue"></param>
		/// <param name="dicData"></param>
		public static TValue DictionaryToValue<TValue>(this TValue tValue, Dictionary<string, object> dicData) where TValue : class
		{
			foreach (var item in dicData)
			{
				var names = item.Key.ToArray('_');
				SetValue(tValue, names, item.Value);
			}
			return tValue;
		}
		/// <summary>
		/// 字典映射成对象
		/// 找到属性所在的层级然后设置值
		/// </summary>
		private static void SetValue(object value, string[] names, object target)
		{
			Type type = value.GetType();
			PropertyInfo propertyInfo = null;
			FieldInfo fieldInfo = null;

			object lastObject = value;
			int i = 0;
			lastObject = GetPropertyValue(names,type,lastObject,out propertyInfo);
			if (propertyInfo != null)
			{

				if (propertyInfo.PropertyType != target.GetType())
				{
					SimpleInitialize.GetCheckType().SetValue(propertyInfo,target,lastObject);
				}
				else
				{
					propertyInfo.SetValue(lastObject,target);
				}
			}
			else
			{
				lastObject = GetFieldValue(names, type, lastObject,out fieldInfo);

				if (fieldInfo!=null)
				{
					if (fieldInfo.FieldType != target.GetType())
					{
						SimpleInitialize.GetCheckType().SetValue(fieldInfo, target, lastObject);
					}
					else
					{
						fieldInfo.SetValue(lastObject,target);
					}
				}
			}
		}

		/// <summary>
		/// 获取对象字段的值支持多层级
		/// </summary>
		/// <param name="names"></param>
		/// <param name="type"></param>
		/// <param name="source"></param>
		/// <param name="fieldInfo"></param>
		/// <returns></returns>
		public static object GetFieldValue(string[] names,Type  type,object source,out FieldInfo fieldInfo)
		{
			fieldInfo = null;
			int i = 0;
			object target=source;
			foreach (var item in names)
			{
				fieldInfo = type.GetFields().FirstOrDefault(p => p.GetColName() == item);
				if (fieldInfo != null)
				{
					type = fieldInfo.FieldType;
				}
				if (i < names.Length - 1)
				{
					target = fieldInfo.GetValue(target);

					if (SimpleCheck.IsNull(target))
					{
						target = Activator.CreateInstance(type);
					}
				}
				i++;
			}
			return target;
		}

		/// <summary>
		/// 获取对象属性值
		/// 支持多层级
		/// </summary>
		/// <param name="names"></param>
		/// <param name="type"></param>
		/// <param name="source"></param>
		/// <param name="property"></param>
		/// <returns></returns>
		public static object GetPropertyValue(string[] names, Type type, object source,out PropertyInfo property)
		{
			property = null;
			int i = 0;
			object target = source;
			foreach (var item in names)
			{
				property = type.GetProperties().FirstOrDefault(p => p.GetColName() == item);
				if (property != null)
				{
					type = property.PropertyType;
				}
				if (i < names.Length - 1)
				{
					var o = property.GetValue(target);
					if (SimpleCheck.IsNull(o))
					{
						 o=Activator.CreateInstance(type);
						property.SetValue(target, o);
						target = o;
					}
				}
				i++;
			}
			return target;
		}
	}
}
